﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TankIt.Models
{
    public class Card : IComparable<Card>
    {
        public enum Suit
        {
            Hearts = 0,
            Spades = 1 << 4,
            Clubs = 2 << 4,
            Diamonds = 3 << 4,
        }

        public enum Value
        {
            Ace = 0,
            Two = 1,
            Three = 2,
            Four = 3,
            Five = 4,
            Six = 5,
            Seven = 6,
            Eight = 7,
            Nine = 8,
            Ten = 9,
            Jack = 10,
            Queen = 11,
            King = 12
        }

        public enum BackColour
        {
            Red = 1,
            Black = 2
        }

        private int cardNumber;

        public Suit CSuit
        {
            get { return this.GetSuit(); }
        }

        public Value CValue
        {
            get { return this.GetValue(); }
        }

        public Card(Suit Suit, Value Value)
        {
            this.cardNumber = (int)Value ^ (int)Suit;

            if (cardNumber > 60) //Highest card number is 111100 (60)
                throw new ArgumentOutOfRangeException("Invalid Card Selection");
        }

        /// <summary>
        /// Return a number between 0 and 60 for every card in the deck.
        /// Using a bitmask
        /// of 0x3F (11 1111), the first two bits represent the suit the last 4 the rank
        /// </summary>
        /// <returns>Integer representing card</returns>
        public int GetCardNumber()
        {
            return GetCardNumber(this);
        }

        public static int GetCardNumber(Card card)
        {
            int temp = (int)card.CValue ^ (int)card.CSuit;
            return temp;
        }

        /// <summary>
        /// This performs some bit mask shifts to clear out the card value to 0000, so that we can
        /// convert the card number to a suit
        /// </summary>
        /// <param name="card">Type of Card</param>
        /// <example>
        /// Card Number: 60
        /// Binary: 111100
        /// 
        /// First two bits: 11xxxx represent 3 which is diamonds
        /// to isolate these whe shift all bits to the right leaving us with: 11
        /// then to match the enum we need to pad 0s back in. 4 of them. So we shift left by 4
        /// 110000, this is then converted to enum
        /// </example>
        /// <returns>Returns a member of the enum Suits</returns>
        /// 
        public static Suit GetSuit(Card card)
        {
            return (Suit)((card.GetCardNumber() >> 4) << 4);
        }
        private Suit GetSuit()
        {
            return GetSuit(this);
        }

        /// <summary>
        /// This removes the 2 suit bits, if present.
        /// This is done with a bitwise AND (&) mask of 1111 (15)
        /// </summary>
        /// <param name="card">Type of Card</param>
        /// <returns>Returns member of Value enum</returns>
        public static Value GetValue(Card card)
        {
            Value temp = (Value)(card.GetCardNumber() & 15);
            return temp;
        }

        private Value GetValue()
        {
            return GetValue(this);
        }

        public char SuitToChar()
        {
            switch (this.GetSuit())
            {
                case Suit.Clubs:
                    return '\u2663';
                case Suit.Diamonds:
                    return '\u2666';
                case Suit.Hearts:
                    return '\u2665';
                case Suit.Spades:
                    return '\u2660';
            }
            return '\0';
        }
        public string ValueToShortString()
        {
            switch (this.GetValue())
            {
                case Value.Ace:
                    return "A";
                case Value.King:
                    return "K";
                case Value.Queen:
                    return "Q";
                case Value.Jack:
                    return "J";
                case Value.Ten:
                    return "T";
            }

            return "" + ((int)this.GetValue());
        }

        public string ToShortString()
        {
            return ValueToShortString() + SuitToChar().ToString();
        }

        public override string ToString()
        {
            return this.GetValue().ToString() + " of " + this.GetSuit().ToString();
        }

        public int CompareTo(Card that)
        {
            return this.GetValue().CompareTo(that.CValue);
        }
        
    }
}